/******************************************************************************
** 公司名称：天津柯迪斯科技有限公司
** 版权信息：
** 文件名称： App_Protocol_TS.c
** 模块名称： 同盛协议处理模块
** 版 本 号： V1.0
** 作    者： 蒲磊
**
** 修改记录： 版本     修改人      时间         修改内容
              V1.0     蒲磊       2023.03.30    初版
******************************************************************************/

/******************************************************************************
* 头文件
******************************************************************************/
#include <string.h>
#include "Config.h"
#include "App_Protocol.h"
#include "App_MainTask.h"
#include "App_Parameter.h"
/******************************************************************************
* 本文件宏定义 ('#define')
******************************************************************************/
#define FRAME_LEN_MAX		100		/*最大帧长度*/
#define LOOP_CYCLE          25      /*Loop函数轮询周期，单位ms*/
/******************************************************************************
* 本文件类型定义 ('typedef')
******************************************************************************/

/******************************************************************************
* 本文件静态函数声明 ('static')
******************************************************************************/
static void vPROTOCOL_Factory_Command(void);
static void vPROTOCOL_Get_Data_TS(void);
static void vPROTOCOL_Send_TS(void);



/******************************************************************************
* 全局变量定义
******************************************************************************/
uint8_t 				gucRx_Buffer[FRAME_LEN_MAX] = {0};
uint8_t 				gucTx_Buffer[FRAME_LEN_MAX] = {0};
uint8_t 				gucRx_Frame_OK 				= 0;
uint16_t 				gusRx_Len 					= 0;
stRECEIVED_DATA			gtReceived_Data 			= {0};
stSEND_DATA				gtSend_Data					= {0};

uint8_t					gucTimeOutError 			= 0;
uint32_t                gulCommunicationCnt 		= 0;

uint8_t                 gucReceivedConfigFrame = 0;/*是否已接收到配置帧标记*/
uint8_t                 gucRequestSendConfigData = 0;/*请求发送配置帧标记*/
uint8_t                 gucStartReceive = 0;		/*是否开始接收标志*/
uint8_t                 gucReceiveCnt = 0;			/*接收计数*/
/*****************************************************************************
* 函数实现 - global ('extern') and local ('static')
******************************************************************************/


/******************************************************************************
** 功  能：获取一帧协议数据
** 参  数：pData-指向数据的指针，Len-数据长度
** 返回值：无
** 备  注：该函数是协议处理模块对外获取数据的接口，接收到完整一帧后，调用该函数进行处理
******************************************************************************/
void vPROTOCOL_Get_OneFrame(uint8_t *pData,uint16_t Len)
{
    if(Len > 1)		/*如果接收到的数据大于1字节，认为是一个完整帧（DMA+IDLE中断接收），直接放入缓存进行处理*/
    {
        memcpy(gucRx_Buffer,pData,Len);		/*将数据拷贝到缓冲区*/
        gusRx_Len = Len;					/*数据长度*/
        gucRx_Frame_OK = 1;					/*接收到一帧标志置1*/
        gucStartReceive = 0;
    }
    else	/*如果只接收到1个字节，认为控制器是按照单个字节发送，则利用帧间超时来判断一帧接收完毕*/
    {
        if(gucStartReceive == 0)
        {
            gucStartReceive = 1;		/*标记开始接收*/
            gucReceiveCnt = 0;
        }
        gucRx_Buffer[gucReceiveCnt] = *pData;
        if(++gucReceiveCnt > FRAME_LEN_MAX)
        {
            gucReceiveCnt = 0;
            gucStartReceive = 0;
        }
    }
}

/******************************************************************************
** 功  能：解析协议数据
** 参  数：无
** 返回值：无
** 备  注：该函数在主函数中被循环调用。用于解析接收到的协议数据
******************************************************************************/
void vPROTOCOL_Loop(void)
{
    static uint16_t lusCnt = 0;
    static uint8_t  lucReadBatCnt = 0;
    static uint8_t  lucReceiveCnt = 0;	/*用于保存上一次的接收计数*/

    if(gucStartReceive == 1)
    {
        if((gucReceiveCnt > 0) && (gucReceiveCnt == lucReceiveCnt))
        {
            gucStartReceive = 0;
            gusRx_Len = gucReceiveCnt;
            gucRx_Frame_OK = 1;
            gucReceiveCnt = 0;
        }
        else
        {
            lucReceiveCnt = gucReceiveCnt;
        }
    }
    else
    {
    }

    if(gucRx_Frame_OK == 1)
    {
        gulCommunicationCnt = ulBsp_Getticks();
        gucTimeOutError = 0;
        if(gucRx_Buffer[0] == 0x3A && gucRx_Buffer[1] == 0x1C)
        {
            /*内部控制指令*/
            vPROTOCOL_Factory_Command();
        }
        else
        {
            /*调用不同的协议进行解析*/
            vPROTOCOL_Get_Data_TS();

        }
        gucRx_Frame_OK = 0;
    }
    else
    {

        /*通讯超时时间，10s*/
        if(ulBsp_Getticks() - gulCommunicationCnt > 10000)
        {
            gucTimeOutError = 1;
            gtReceived_Data.Speed_Cnt = 0;  /*确保返回速度为0*/
        }

    }
    /*500ms发送一次数据。根据Loop函数的调用周期，计算次数*/
    if(++lusCnt > (100 / LOOP_CYCLE) -1)
    {
        lusCnt = 0;
        vPROTOCOL_Send_TS();
    }
}

/******************************************************************************
** 功  能：设置大灯状态
** 参  数：State-大灯状态。0-关闭，1-打开
** 返回值：无
** 备  注：所有协议通用
******************************************************************************/
void vPROTOCOL_Set_Lamp(uint8_t State)
{
    gtSend_Data.Lamp = State == 0 ? 0 : 1;
}



/******************************************************************************
** 功  能：设置档位
** 参  数：Pas-档位值，最大为9，最小为-1,-1表示助推档
** 返回值：无
** 备  注：本函数不对档位值的合理性做检查。请保证传入的档位值正确。
******************************************************************************/
void vPROTOCOL_Set_Pas(int8_t Pas)
{
    if(Pas > -1)
    {
        if(Pas == 0)
        {
            gtSend_Data.Pas = 0;
        }
        else
        {
            if(gtSend_Data.MaxPas == 5)
            {
                gtSend_Data.Pas = Pas;
            }
            else if(gtSend_Data.MaxPas == 4)
            {
                gtSend_Data.Pas = Pas + 1;
            }
            else if(gtSend_Data.MaxPas == 3)
            {
                gtSend_Data.Pas = Pas + 2;
            }
        }
        gtSend_Data.Push = 0;
    }
    else
    {
        gtSend_Data.Push = 1;
    }
}

/******************************************************************************
** 功  能：设置档位范围
** 参  数：MaxPas-最大挡位
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Pas_Range(int8_t MaxPas)
{
    gtSend_Data.MaxPas = MaxPas;
}

/******************************************************************************
** 功  能：设置限速值
** 参  数：Speed-限速值，1km/h
** 返回值：无
** 备  注：本函数不对传入值的合理性做检查。请保证传入的值正确。
******************************************************************************/
void vPROTOCOL_Set_Speed_Limit(uint16_t Speed)
{
    gtSend_Data.Speed_Limit = Speed;
}

/******************************************************************************
** 功  能：设置轮径
** 参  数：Wheel-轮径值
** 返回值：无
** 备  注：为了和其它协议兼容，传入的轮径值是实际值的10倍
******************************************************************************/
void vPROTOCOL_Set_Wheel(uint16_t Wheel)
{
    gtSend_Data.Wheel_Diameter = Wheel / 10;
}



/******************************************************************************
** 功  能：获取当前电流值
** 参  数：无
** 返回值：实际电流值的10倍。比如实际电流12.3A，返回123
** 备  注：所有协议通用
******************************************************************************/
uint16_t usPROTOCOL_Get_Current(void)
{
    if(gucTimeOutError == 1)
    {
        return 0;
    }
    else
    {
        return gtReceived_Data.Current * 2;
    }
}

/******************************************************************************
** 功  能：获取电量SOC
** 参  数：无
** 返回值：实际电量值，-1表示不支持SOC。
** 备  注：所有协议通用
******************************************************************************/
int8_t cPROTOCOL_Get_Soc(void)
{
    uint8_t Soc_Tab[] = {0,8,16,25,33,41,50,58,66,75,83,91,100};
    if(gtReceived_Data.Volt_Level >= 12)
    {
        return 100;
    }
    else
    {
        return Soc_Tab[gtReceived_Data.Volt_Level];
    }
}

/******************************************************************************
** 功  能：获取当前车速
** 参  数：无
** 返回值：实际车速*10.比如返回120，实际车速即12.0Km/h
** 备  注：所有协议通用
******************************************************************************/
uint16_t usPROTOCOL_Get_Speed(void)
{
    if(gtReceived_Data.Speed_Cnt >= 0x06D6 || gtReceived_Data.Speed_Cnt == 0 || gucTimeOutError == 1)
    {
        /*如果车轮转动一周的时间大于等于3500，或者等于0，或者通讯超时，即认为速度为0*/
        return 0;
    }
    else
    {
        if(gtSend_Data.Wheel_Diameter == 27 && ((CONFIG_27INCH_DISPLAY == DISPLAY_700C) || (CONFIG_27INCH_DISPLAY == DISPLAY_275)))
        {
            /*轮径27，按照27.5Inch计算，周长698.5mm，698.5*314*36/100=78958*/
            return 78958 / (gtReceived_Data.Speed_Cnt * 2);
        }
        else
        {
            /*其它轮径，按照英寸计算，1inch=25.4mm，25.4*314*36/100=2871*/
            return 2871 * gtSend_Data.Wheel_Diameter / (gtReceived_Data.Speed_Cnt * 2);
        }
    }
}

/******************************************************************************
** 功  能：获取错误代码
** 参  数：无
** 返回值：十六进制的错误代码
** 备  注：包括30错误代码（通信超时）
**         所有协议通用
******************************************************************************/
uint8_t ucPROTOCOL_Get_Errcode(void)
{
    static const char gucArrErrorCode[] = {0x02,0x03,0x04,0x06,0x08};
    uint8_t i;
    if(gucTimeOutError == 1)
    {
        return 0x30;
    }
    else
    {
        for(i = 0; i < sizeof(gucArrErrorCode); i++)
        {
            if(gucArrErrorCode[i] == gtReceived_Data.ErrCode)
            {
                return gtReceived_Data.ErrCode;
            }
        }
        return 0;
//        if(gtReceived_Data.ErrCode < 11 && gtReceived_Data.ErrCode != 3)
//        {
//            return gtReceived_Data.ErrCode;
//        }
//        else
//        {
//            return 0;
//        }
    }
}

/******************************************************************************
** 功  能：工厂指令的应答
** 参  数：Cmd-要应答的指令，Response-要应答的参数
** 返回值：无
** 备  注：
******************************************************************************/
static void vPROTOCOL_Factory_Response(uint8_t Cmd,uint16_t Response)
{
    uint8_t lucRxBuffer[8];


    lucRxBuffer[0] = 0x3A;  /*0x3A,0x50是应答帧的帧头*/
    lucRxBuffer[1] = 0x50;
    lucRxBuffer[2] = Cmd;
    lucRxBuffer[3] = Response & 0x00FF;
    lucRxBuffer[4] = (Response >> 8) & 0x00FF;
    lucRxBuffer[5] = lucRxBuffer[2] + lucRxBuffer[3] + lucRxBuffer[4]; /*8位的和校验*/
    lucRxBuffer[6] = 0x0D;
    lucRxBuffer[7] = 0x0A;  /*0x0D,0x0A是固定帧尾*/

    USART_MCU_Send_Frame(lucRxBuffer,8);

}


/******************************************************************************
** 功  能：工厂指令的解析
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Factory_Command(void)
{
    uint16_t n;
    uint16_t lusCheckSum = 0;
    uint16_t lusResponse;

    for(n = 0; n < gusRx_Len - 5; n++)
    {
        lusCheckSum += gucRx_Buffer[1 + n];		/*计算校验值，和校验*/
    }
    if((gucRx_Buffer[3] == gusRx_Len - 8) && (lusCheckSum == gucRx_Buffer[gucRx_Buffer[3] + 5] * 256UL + gucRx_Buffer[gucRx_Buffer[3] + 4]))
    {
        switch(gucRx_Buffer[2])
        {
        case 0x5D:		/*电压校准*/
        {
            lusResponse = vVoltage_Calibration();
            vPROTOCOL_Factory_Response(0x5D,lusResponse);
            break;
        }
        case 0x8E:		/*清除ODO*/
        {
            vClear_ODO();
            vPROTOCOL_Factory_Response(0x8E,5678); /*5678是针对清ODO的固定响应*/
            break;
        }
        case 0x6E:		/*校准光感*/
        {
            lusResponse = vPhotoDiode_Calibration();
            vPROTOCOL_Factory_Response(0x6E,lusResponse);
            break;
        }
        case 0x71:		/*自动校准时间*/
        {
            vDateTime_Calibration(gucRx_Buffer[7],gucRx_Buffer[8],gucRx_Buffer[9],gucRx_Buffer[4],gucRx_Buffer[5],gucRx_Buffer[6]);
            vPROTOCOL_Factory_Response(0x71,1234); /*1234是针对校准时间的固定响应*/
            break;
        }
        default:
            break;
        }
    }
}


/******************************************************************************
** 功  能：解析TS协议数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
static void vPROTOCOL_Get_Data_TS(void)
{
    uint8_t Checksum = 0;
    uint8_t n;
    for(n = 0; n < 8; n++)
    {
        Checksum += gucRx_Buffer[n];	/*计算校验值*/
    }
    /*首字节是67，并且校验正确，认为接收数据无误*/
    if(gucRx_Buffer[0] == 67 && gucRx_Buffer[gusRx_Len - 1] == Checksum)
    {
        gtReceived_Data.Volt_Level	        = gucRx_Buffer[1];					/*电量值*/
        //gtReceived_Data.Current		= gucRx_Buffer[2] * 10 / 3;			/*实际电流值 = 接收到的值 / 3.扩大10倍输出*/
        gtReceived_Data.LowBattery          = gucRx_Buffer[2] & 0x01;			/*欠压标志*/
        gtReceived_Data.Motor_State         = gucRx_Buffer[2] & 0x04;			/*电机状态*/
        gtReceived_Data.Speed_Sensor_State  = gucRx_Buffer[2] & 0x08;		/*中轴速度传感器状态*/
        gtReceived_Data.Torque_Voltage_1    = gucRx_Buffer[3];				/*力矩电压值1*/
        gtReceived_Data.Current             = 0; //gucRx_Buffer[4];				/*力矩电压值2*/
        gtReceived_Data.ErrCode	            = gucRx_Buffer[5];						/*错误代码*/
        gtReceived_Data.Speed_Cnt	        = (uint16_t)gucRx_Buffer[7] << 8 | gucRx_Buffer[6];		/*车轮转动一周的脉冲时间*/

    }

    return;
}

/******************************************************************************
** 功  能：发送TS协议数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
static void vPROTOCOL_Send_TS(void)
{
    uint8_t lucCheckSum = 0;
    uint8_t n;


    gucTx_Buffer[0] = 89;						/*固定89*/
    gucTx_Buffer[1] = 0x00;
    if(gtSend_Data.Push == 1)
    {
        gucTx_Buffer[1] |= 0x20;
    }
    else
    {
        if(gtSend_Data.Pas == 0)
        {
            gucTx_Buffer[1] |= 0x10;
        }
        else if(gtSend_Data.Pas == 1)
        {
            gucTx_Buffer[1] |= 0x80;
        }
        else if(gtSend_Data.Pas == 2)
        {
            gucTx_Buffer[1] |= 0x40;
        }
        else if(gtSend_Data.Pas == 3)
        {
            gucTx_Buffer[1] |= 0x02;
        }
        else if(gtSend_Data.Pas == 4)
        {
            gucTx_Buffer[1] |= 0x04;
        }
        else if(gtSend_Data.Pas == 5)
        {
            gucTx_Buffer[1] |= 0x08;
        }
    }
    gucTx_Buffer[1] |= (gtSend_Data.Lamp & 0x01);		/*大灯*/
    gucTx_Buffer[2] = gtSend_Data.MaxPower;				/*最大功率*/
    gucTx_Buffer[3] = gtSend_Data.Wheel_Diameter;		/*轮径，1英寸*/
    gucTx_Buffer[4] = 0;								/*正常时发0*/
    gucTx_Buffer[5] = gtSend_Data.Speed_Limit;			/*限速值，1km/h*/

    for(n = 0; n < 6; n++)
    {
        lucCheckSum += gucTx_Buffer[n];
    }


    gucTx_Buffer[6] = lucCheckSum;


    USART_MCU_Send_Frame(gucTx_Buffer,7);		/*发送数据*/

}

/******************************************************************************
** 功  能：复位通信超时计数变量
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_ResetCommunicationOverTime(void)
{
    __disable_irq();
    gucTimeOutError = 0;
    gulCommunicationCnt = ulBsp_Getticks();
    __enable_irq();

}


/******************************************************************************
** 功  能：开机上电时，设置默认要发送给控制器的数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Value_When_PowerOn(void)
{
    vPROTOCOL_Set_Wheel(usGet_Wheel_Size(gtParam.Wheel_Diameter));
    vPROTOCOL_Set_Pas_Range(gtParam.Pas_Max);
    vPROTOCOL_Set_Pas(0);/*开机LOGO界面发0档*/
    vPROTOCOL_Set_Speed_Limit(gtParam.Speed_Limit);

}

/******************************************************************************
** 功  能：退出设置时，设置默认要发送给控制器的数据
** 参  数：无
** 返回值：无
** 备  注：
******************************************************************************/
void vPROTOCOL_Set_Value_When_ExitSetting(void)
{
    vPROTOCOL_Set_Wheel(usGet_Wheel_Size(gtParam.Wheel_Diameter));
    vPROTOCOL_Set_Speed_Limit(gtParam.Speed_Limit);
}

/******************************************************************************
** 功  能：设置发送配置数据
** 参  数：无
** 返回值：无
** 备  注：本函数运行后，即开始发送配置数据。直到再次设置发送运行数据或停止
**         所有协议通用
******************************************************************************/
void vPROTOCOL_Send_Config_Data(void)
{

}
/******************************************************************************
** 功  能：设置发送一次配置数据
** 参  数：无
** 返回值：无
** 备  注：本函数运行后，只发送一次配置数据。然后会转为发送运行数据
**         所有协议通用
******************************************************************************/
void vPROTOCOL_Send_Config_Data_OneTime(void)
{

}